package com.seaengine.resourcemanager
{
	import com.seaengine.util.SmartURL;
	import com.seaengine.util.StringUtils;
	
	import flash.display.BitmapData;
	import flash.display.LoaderInfo;
	import flash.errors.IllegalOperationError;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.net.URLRequest;
	import flash.system.ApplicationDomain;
	import flash.system.LoaderContext;
	import flash.system.SecurityDomain;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;
	import com.seaengine.resourcemanager.loader.ResourceCacheLoader;
	import com.seaengine.resourcemanager.loader.XMLCacheLoader;

	public class ResSystem
	{
		//单件
		private static var s_Instance:ResSystem;
		private static var m_bSingleton:Boolean = true;
		//资源列表
		private var m_Res_Map:Dictionary;
		//资源锁定列表
		private var m_ResLocked_Map:Dictionary;
		//资源固定存在列表
		private var m_ResCanNotDispose_Map:Dictionary;
		//加载列表        
		private var m_loadingList:Dictionary;
		//回调列表
		private var m_callbackList:Dictionary;
		private var m_callbackArgs:Dictionary;
		private var m_callbackProgressList:Dictionary; /**进度*/
		//预加载列表
		private var m_preLoadingList:Array;
		//当前加载数
		protected var m_currentLoadingNum:int = 0;
		//保存 程序域
		private var _loadDomain:Dictionary = new Dictionary();
		private var lc:LoaderContext;
		//最大的重试次数
		protected const MAX_RETRY_TIMES:int = 5;
		//最大的并行夹加载数
		protected const MAX_CONCURRENT_LOADING:int = 3;

		public function ResSystem()
		{
			if (m_bSingleton)
			{
				throw new Error("只能用getInstance()来获取实例");
			}
			init();
		}

		public static function getInstance():ResSystem
		{
			if (!s_Instance)
			{
				m_bSingleton = false;
				s_Instance = new ResSystem();
				m_bSingleton = true;
			}
			return s_Instance;
		}
		
		
		/**
		 * 初始化处理
		 * 
		 */
		private function init():void
		{
			m_Res_Map = new Dictionary();
			m_ResLocked_Map = new Dictionary();
			m_ResCanNotDispose_Map = new Dictionary();
			m_loadingList = new Dictionary();
			m_callbackList = new Dictionary();
			m_callbackArgs = new Dictionary();
			m_callbackProgressList = new Dictionary();
			m_preLoadingList = new Array();
		}

		/**
		 * 清除未使用，并且不是长期保存的资源 
		 * 
		 */
		public function clearUnUsed():void
		{
			for (var k:Object in m_Res_Map)
			{
				var key:String = k.toString();
				if (m_ResLocked_Map[key] == null && m_ResCanNotDispose_Map[key] == null)
				{
					delete m_Res_Map[key];
				}
			}
		}

		/**
		 * 从其他程序域取得BitmapData 
		 * @param lib
		 * @param className
		 * @return 
		 * 
		 */
		public function getAppDomainBitmapData(lib:String,className:String):BitmapData
		{
		  try
		  {
		  	var bmpData:Class = _loadDomain[lib].getDefinition(className) as Class;
			var ba:BitmapData = new bmpData(0,0);
			return ba;
		  }
		  catch (e:Error)
		  {
		  	
		  	return m_Res_Map[lib].getBitmapData(className);
			
		    //throw new IllegalOperationError(className + " definition not found in " + lib);
		  }
		  return null;
		}

		/**
		 * 清除，释放资源 
		 * @param _str 资源的url或名称
		 * 
		 */
		public function unloadRes(_str:String):void
		{
			var _parsedURL:SmartURL = new SmartURL(_str);
			var _fileName:String = _parsedURL.tofile();
			//			var _fileName:String = StringUtils.extractFileNameFromUrl( _str);
			if (m_ResLocked_Map[_fileName] == null && m_ResCanNotDispose_Map[_fileName] == null)
			{
				//trace("delete file:"+_fileName)
				delete m_Res_Map[_fileName];
			}
		}

		/**
		 * 取得资源 
		 * @param _path 资源路径
		 * @param _onCallback 回调函数
		 * @param _obj 传入的参数，在回调函数中做参数
		 * @param canNotDispose 是否可被释放
		 * @param _onProgress 进度回调函数
		 * @return 指定的资源
		 * 
		 */
		public function getRes(_path:String, _onCallback:Function, _obj:Object = null, canNotDispose:Boolean = false, _onProgress:Function = null):Object
		{
			var _parsedURL:SmartURL = new SmartURL(_path);
			var _fileName:String = _parsedURL.tofile();
			var _ExtensionName:String = StringUtils.extractExtensionNameFromFileName(StringUtils.extractFileNameFromUrl(_path));
			var _type:String = getType(_ExtensionName);
			m_ResLocked_Map[_fileName] = true;
			if (canNotDispose)
				m_ResCanNotDispose_Map[_fileName] = true;
			
			if (_onProgress != null)/**no zero progress*/
			{
				var e:ProgressEvent = new ProgressEvent(ProgressEvent.PROGRESS, false, false, 0, 1);
				_onProgress(e);
			}
			
			var _resObj:Object = m_Res_Map[_fileName];
			if (_resObj != null)
			{
				//如果有缓存在m_Res_Map里
				if (_onCallback != null)
				{
					if (_obj != null)
					{
						_onCallback(_fileName, _resObj, _obj);
					}
					else
					{
						_onCallback(_fileName, _resObj);
					}
				}
				delete m_ResLocked_Map[_fileName];

				if (_onProgress != null)
				{
					e = new ProgressEvent(ProgressEvent.PROGRESS, false, false, 1, 1);
					_onProgress(e);
				}

				return _resObj;
			}
			//如果m_Res_Map里没缓存
			if (m_callbackList[_fileName] != null)
			{
				if (_onCallback != null)
					(m_callbackList[_fileName] as Array).push(_onCallback);
				if (_onCallback != null)
					(m_callbackArgs[_fileName] as Array).push(_obj);
				if (_onProgress != null)
					(m_callbackProgressList[_fileName] as Array).push(_onProgress);
				return null;
			}

			m_callbackList[_fileName] = new Array();
			if (_onCallback != null)
				(m_callbackList[_fileName] as Array).push(_onCallback);

			m_callbackArgs[_fileName] = new Array();
			if (_onCallback != null)
				(m_callbackArgs[_fileName] as Array).push(_obj);

			m_callbackProgressList[_fileName] = new Array();
			if (_onProgress != null)
				(m_callbackProgressList[_fileName] as Array).push(_onProgress);

			var resCacheRequest:ResourcCaheRequest = new ResourcCaheRequest(_path, _type);
			//把请求放到准备加载的列表中去
			m_preLoadingList.push(resCacheRequest);

			doLoad();
			return null;
		}

		/**
		 * 加载资源 
		 * 
		 */
		protected function doLoad():void
		{
			while (m_currentLoadingNum < MAX_CONCURRENT_LOADING && m_preLoadingList.length > 0)
			{
				var resCaheRequest:ResourcCaheRequest = m_preLoadingList.shift() as ResourcCaheRequest;
				doComonLoad(resCaheRequest, onLoaded, onIOError, onProgress);
			}
		}
		
		/**
		 * 加载成功处理 
		 * @param event
		 * 
		 */
		protected function onLoaded(event:Event):void
		{
			doCommonLoaded(event, onLoaded, onIOError, onProgress);
		}
		
		/**
		 * 加载失败处理 
		 * @param event
		 * 
		 */
		protected function onIOError(event:IOErrorEvent):void
		{
			doCommonIOError(event, onLoaded, onIOError, onProgress);
		}
		
		/**
		 * 加载进度处理 
		 * @param event
		 * 
		 */
		protected function onProgress(event:ProgressEvent):void
		{
			doCommonProgress(event);
		}
		
		/**
		 * 根据资源类型，分别用不同的加载器加载。 
		 * @param _req
		 * @param _successfn
		 * @param _erroefn
		 * @param _progressfn
		 * 
		 */
		protected function doComonLoad(_req:ResourcCaheRequest, _successfn:Function, _erroefn:Function, _progressfn:Function):void
		{
			//var _fileName:String = StringUtils.extractFileNameFromUrl(_req.m_url);
			var LoaderClass:Class = getLoaderClass(_req.m_requestType);
			var resLoader:* = new LoaderClass(_req.m_url, _req); /**ResourceCacheLoader, XMLCacheLoader*/
			m_loadingList[_req.m_url] = resLoader;
			if (LoaderClass == ResourceCacheLoader)
			{
				resLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, _successfn);
				resLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, _erroefn);
				resLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, _progressfn);
			}
			else
			{
				resLoader.addEventListener(Event.COMPLETE, _successfn);
				resLoader.addEventListener(IOErrorEvent.IO_ERROR, _erroefn);
				resLoader.addEventListener(ProgressEvent.PROGRESS, _progressfn);
			}
			if(_req.m_requestType == "swf")
			{
				var _fileNamee:String = _req.m_url;
				_fileNamee=_fileNamee.split("?")[0];
				var _parsedURL:SmartURL = new SmartURL(_fileNamee);
				var _fileName:String = _parsedURL.tofile();
				lc = new LoaderContext();
				//加到system domian下的一个applicatiodomain，而不是当前的domain或子domian
				lc.applicationDomain = new ApplicationDomain();    
				_loadDomain[_fileName] = lc.applicationDomain
				resLoader.load( new URLRequest(_req.m_url),lc);
			}
			else
				resLoader.load( new URLRequest(_req.m_url));
			m_currentLoadingNum++;
		}

		
		/**
		 * 资源取得后的处理 
		 * @param event
		 * @param _successfn
		 * @param _erroefn
		 * @param _progressfn
		 * 
		 */
		protected function doCommonLoaded(event:Event, _successfn:Function, _erroefn:Function, _progressfn:Function):void
		{
			var resLoader:*;
			if (event.target is XMLCacheLoader)
				resLoader = event.target as XMLCacheLoader;
			else
			{
				var _loaderInfo:LoaderInfo = event.target as LoaderInfo;
				resLoader = _loaderInfo.loader as ResourceCacheLoader;
			}

			var _fileName:String = getFileName(resLoader.m_fileName);

			switch ((resLoader.m_req as ResourcCaheRequest).m_requestType)
			{
				case 'image':
				case 'swf':
					m_Res_Map[_fileName] = (event.target as LoaderInfo).content;
					break;
				case 'text':
					m_Res_Map[_fileName] = new XML(resLoader.data);
					break;
				case 'byt':
					var byteTemp:ByteArray = new ByteArray();
					byteTemp.writeBytes(resLoader.data, 0, resLoader.bytesLoaded);
					m_Res_Map[_fileName] = byteTemp;
					break;
			}

			if (resLoader is ResourceCacheLoader)
			{
				resLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, _successfn);
				resLoader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, _erroefn);
				resLoader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, _progressfn);
			}
			else
			{
				resLoader.removeEventListener(Event.COMPLETE, _successfn);
				resLoader.removeEventListener(IOErrorEvent.IO_ERROR, _erroefn);
				resLoader.removeEventListener(ProgressEvent.PROGRESS, _progressfn);
			}

			var _CallbackFns:Array = m_callbackList[_fileName] as Array;
			var _callBackObj:Array = m_callbackArgs[_fileName] as Array;

			//调用回调函数
			for (var i:Number = 0; i < _CallbackFns.length; i++)
			{
				if (_callBackObj[i] != null)
					_CallbackFns[i](_fileName, m_Res_Map[_fileName], _callBackObj[i]);
				else
					_CallbackFns[i](_fileName, m_Res_Map[_fileName]);
			}
			m_callbackList[_fileName] = null;
			delete m_callbackList[_fileName];
			delete m_ResLocked_Map[_fileName];
			m_callbackArgs[_fileName] = null;
			delete m_callbackArgs[_fileName];
			delete m_callbackProgressList[_fileName];

			m_loadingList[_fileName] = null;
			delete m_loadingList[_fileName];
			m_currentLoadingNum--;
			//继续加载加载队里中其他的的资源
			doLoad();
		}

		protected function doCommonIOError(event:IOErrorEvent, _successfn:Function, _erroefn:Function, _progressfn:Function):void
		{
			var resLoader:*;
			if (event.target is XMLCacheLoader)
				resLoader = event.target as XMLCacheLoader;
			else
			{
				var _loaderInfo:LoaderInfo = event.target as LoaderInfo;
				resLoader = _loaderInfo.loader as ResourceCacheLoader;
			}

			var _fileName:String = getFileName(resLoader.m_fileName);

			var _resReq:ResourcCaheRequest = resLoader.m_req;
			if (_resReq.m_retriedTimes > MAX_RETRY_TIMES)
			{
				if (resLoader is ResourceCacheLoader)
				{
					resLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, _successfn);
					resLoader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, _erroefn);
					resLoader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, _progressfn);
				}
				else
				{
					resLoader.removeEventListener(Event.COMPLETE, _successfn);
					resLoader.removeEventListener(IOErrorEvent.IO_ERROR, _erroefn);
					resLoader.removeEventListener(ProgressEvent.PROGRESS, _progressfn);
				}

				m_callbackList[_fileName] = null;
				delete m_callbackList[_fileName];
				delete m_ResLocked_Map[_fileName];
				m_callbackArgs[_fileName] = null;
				delete m_callbackArgs[_fileName];
				delete m_callbackProgressList[_fileName];

				m_loadingList[_fileName] = null;
				delete m_loadingList[_fileName];
				trace("Resource IOEROR", _fileName);
				m_currentLoadingNum--;
				doLoad();
			}
			else
			{
				_resReq.m_retriedTimes++;
				resLoader.load(new URLRequest(_resReq.m_url));
			}
		} //end function

		protected function doCommonProgress(event:ProgressEvent):void
		{
			var resLoader:*;
			if (event.target is XMLCacheLoader)
				resLoader = event.target as XMLCacheLoader;
			else
			{
				var _loaderInfo:LoaderInfo = event.target as LoaderInfo;
				resLoader = _loaderInfo.loader as ResourceCacheLoader;
			}

			var _fileName:String = getFileName(resLoader.m_fileName);

			if (m_callbackProgressList[_fileName])
				for each (var fn:Function in m_callbackProgressList[_fileName])
					fn(event);
		}

		protected function getFileName(path:String):String
		{
			var _fileNamee:String = path;
			_fileNamee = _fileNamee.split("?")[0];
//			return _fileNamee;
			var _parsedURL:SmartURL = new SmartURL(_fileNamee);
			var _fileName:String = _parsedURL.tofile();
			return _fileName;
		}

		/**
		 * 根据文件后缀名，确定加载类型 
		 * @param _ext
		 * @return 
		 * 
		 */
		protected function getType(_ext:String):String
		{
			switch (_ext)
			{
				case "jpg":
				case "png":
					return "image";
				case "swf":
					return "swf";
				case "xml":
					return "text";
				case "byt":
				case "fight":
				case "rankfight":
				case "robfight":
				case "chaosfight":
					return "byt";
			}
			return "";
		}

		/**
		 * 根据请求的资源类型，取得相应的加载器 
		 * @param requestType
		 * @return 
		 * 
		 */
		protected function getLoaderClass(requestType:String):Class
		{
			switch (requestType)
			{
				case 'image':
				case 'swf':
					return ResourceCacheLoader;
				case 'text':
				case 'byt':
					return XMLCacheLoader;
			}
			return null;
		}

	}
}
